package org.fjsei.yewu.unit;

import graphql.relay.Connection;
import graphql.schema.DataFetchingEnvironment;
import md.cm.base.Company;
import md.specialEqp.inspect.Isp;
import md.system.User;
//import org.elasticsearch.index.query.BoolQueryBuilder;
import org.fjsei.yewu.graphql.DbPageConnection;
import org.fjsei.yewu.graphql.IdMapper;
import org.fjsei.yewu.index.CompanyEs;
import org.fjsei.yewu.index.PersonEs;
import org.fjsei.yewu.index.PipingUnitEs;
import org.fjsei.yewu.index.UnitEs;
import org.fjsei.yewu.input.UnitCommonInput;
import org.fjsei.yewu.jpa.PageOffsetFirst;
import org.fjsei.yewu.resolver.Comngrql;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.*;
//import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
//import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
//import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
//import org.springframework.data.elasticsearch.core.query.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

//import static org.elasticsearch.index.query.QueryBuilders.*;

@Controller
public class CompanyController extends Comngrql implements IdMapper<Company> {
    @Autowired
    private ElasticsearchOperations esTemplate;


    /**
     * 不能Connection<?> getUnitEsFilter(,)类型必须敲定，graphql不知道什么类型=报错。
     * 原先2021-5-19版本 Iterable<?> getUnitEsFilter(，)都允许啊；
     * graphql模型文件定义union UnitEs= CompanyEs | PersonEs，但这union和java定义我这里UnitEs似乎都没有半点相关的，仅仅同名!!
     * 新版 @Argument 注解的参数必须改成对象封装，可以支持null的。
     */
    @QueryMapping
    public Connection<UnitEs> getUnitEsFilter(@Argument UnitCommonInput where, @Argument Integer first, @Argument String after,
                                              @Argument Integer last, @Argument String before, @Argument String orderBy, @Argument Boolean asc, DataFetchingEnvironment env) {
        User user = checkAuth();
        if (user == null) return null;
        DbPageConnection<Isp> connection = new DbPageConnection(env);
        int offset = connection.getOffset();
        int limit = connection.getLimit();
        Pageable pageable;
        if (!StringUtils.hasLength(orderBy))
            pageable = PageOffsetFirst.of(offset, limit);
        else
            pageable = PageOffsetFirst.of(offset, limit, Sort.by(asc ? Sort.Direction.ASC : Sort.Direction.DESC, orderBy));

        if (where == null) return null;
        List units;
        if (where.isCompany())
            units = getCompanyEsbyFilter(where, pageable);
        else
            units = getPersonEsbyFilter(where, pageable);
        //报错asked for named object type 'UnitEs' but its not an object type but rather a 'graphql.schema.GraphQLUnionType' 类型UnitEs不同 union UnitEs= CompanyEs | PersonEs
        return connection.setListData(units).get(env);
    }

    //就算异步的，也是需要分页参数，不同请求包context变动了?重新查询/数据源主动缓存加速。ES能对Filter过滤器部分自动缓存。
    public List<?> getCompanyEsbyFilter(UnitCommonInput as, Pageable pageable) {
        List<Query> listquerys = new ArrayList<Query>();
        if (StringUtils.hasText(as.getName())){
            listquerys.add(Query.of(q -> q
                    .matchPhrase(m -> m
                            .field("name")
                            .query(as.getName()).slop(1)
                    )
            ));
        }
        if (StringUtils.hasText(as.getNo()))
            listquerys.add(Query.of(q -> q
                    .term(m -> m
                            .field("no").value(as.getNo())
                    )
            ));
        if (StringUtils.hasText(as.getAddress()))
            listquerys.add(Query.of(q -> q
                    .matchPhrase(m -> m
                            .field("address")
                            .query(as.getAddress()).slop(1)
                    )
            ));
        //Elasticsearch 窗口查询4种方式:1 Page分页 max_result_window默认为10000; 2 search_after 单方向游标; 3 scroll 大快照:局限当前连接有状态的才能使用;4:PIT;
        NativeQueryBuilder  nativeQueryBuilder = NativeQuery.builder()
                .withFilter(q -> q.bool(
                                v->v.must(listquerys)
                        )
                );
        NativeQuery query =nativeQueryBuilder.withPageable(pageable).build();
        SearchHits<CompanyEs> searchHits = esTemplate.search(query, CompanyEs.class);
        List<SearchHit<CompanyEs>> hits=searchHits.getSearchHits();
        Iterable<CompanyEs> list= (List<CompanyEs>) SearchHitSupport.unwrapSearchHits(hits);
        String queryDslStr= Objects.toString(query.getFilter(),"空");
        return (List<?>) list;
    }
    /**类似的 Person 版本，
     * ES索引的搜索，Person《= Unit关联。 Person,Company两个模型都没有直接关联Unit
     * */
    public List<?> getPersonEsbyFilter(UnitCommonInput as, Pageable pageable) {
        List<Query> listquerys = new ArrayList<Query>();
        if (StringUtils.hasText(as.getName())){
            listquerys.add(Query.of(q -> q
                    .matchPhrase(m -> m
                            .field("name")
                            .query(as.getName()).slop(0)
                    )
            ));
        }
        if (StringUtils.hasText(as.getNo()))
            listquerys.add(Query.of(q -> q
                    .term(m -> m
                            .field("no").value(as.getNo())
                    )
            ));
        if (StringUtils.hasText(as.getAddress()))
            listquerys.add(Query.of(q -> q
                    .matchPhrase(m -> m
                            .field("address")
                            .query(as.getAddress()).slop(1)
                    )
            ));
        if (StringUtils.hasText(as.getPhone()))
            listquerys.add(Query.of(q -> q
                    .term(m -> m
                            .field("phone").value(as.getPhone())
                    )
            ));
        NativeQueryBuilder  nativeQueryBuilder = NativeQuery.builder()
                .withFilter(q -> q.bool(
                                v->v.must(listquerys)
                        )
                );
        NativeQuery query =nativeQueryBuilder.withPageable(pageable).build();
        SearchHits<PersonEs> searchHits = esTemplate.search(query, PersonEs.class);
        List<SearchHit<PersonEs>> hits=searchHits.getSearchHits();
        Iterable<PersonEs> list= (List<PersonEs>) SearchHitSupport.unwrapSearchHits(hits);
        String queryDslStr= Objects.toString(query.getFilter(),"空");
        return (List<?>) list;
    }

}

